/*
 * Copyright (C) 2005 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.swing.desktop.frame;

import java.awt.Dimension;
import java.awt.Insets;

import javax.swing.DesktopManager;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.JScrollPane;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Sets scrollbars on the main workbench frame if a window is resized/moved
 * outside the visible viewport.
 * 
 * @author $Author: johan $
 * @version $Revision: 1.2 $
 */
public class DesktopScrollbarManager implements DesktopManager
{
	private DesktopManager delegate;
	private JScrollPane desktopScroller;
	private JDesktopPane desktop;
	private Log log = LogFactory.getLog(getClass()) ;

	/**
	 * Intercepts calls to the desktop manager. Allows the workbench to add
	 * scrollbars to the desktop if an internal frame does not fit.
	 * 
	 * @param delegate
	 */
	DesktopScrollbarManager(JDesktopPane desktop) {
		super();
		this.desktop = desktop;
		this.delegate = desktop.getDesktopManager();
		desktopScroller = new JScrollPane(desktop);
		desktop.setDesktopManager(this);
	}

	JScrollPane getDesktopScroller()
	{
		return desktopScroller;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#beginDraggingFrame(javax.swing.JComponent)
	 */
	public void beginDraggingFrame(JComponent f)
	{
		delegate.beginDraggingFrame(f);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#endDraggingFrame(javax.swing.JComponent)
	 */
	public void endDraggingFrame(JComponent f)
	{
		delegate.endDraggingFrame(f);
		resizeDesktop();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#endResizingFrame(javax.swing.JComponent)
	 */
	public void endResizingFrame(JComponent f)
	{
		delegate.endResizingFrame(f);
		resizeDesktop();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#beginResizingFrame(javax.swing.JComponent,
	 *      int)
	 */
	public void beginResizingFrame(JComponent f, int direction)
	{
		delegate.beginResizingFrame(f, direction);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#dragFrame(javax.swing.JComponent, int,
	 *      int)
	 */
	public void dragFrame(JComponent f, int newX, int newY)
	{
		delegate.dragFrame(f, newX, newY);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#resizeFrame(javax.swing.JComponent, int,
	 *      int, int, int)
	 */
	public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
			int newHeight)
	{
		delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#setBoundsForFrame(javax.swing.JComponent,
	 *      int, int, int, int)
	 */
	public void setBoundsForFrame(JComponent f, int newX, int newY,
			int newWidth, int newHeight)
	{
		delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#activateFrame(javax.swing.JInternalFrame)
	 */
	public void activateFrame(JInternalFrame f)
	{
		delegate.activateFrame(f);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#closeFrame(javax.swing.JInternalFrame)
	 */
	public void closeFrame(JInternalFrame f)
	{
		delegate.closeFrame(f);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#deactivateFrame(javax.swing.JInternalFrame)
	 */
	public void deactivateFrame(JInternalFrame f)
	{
		delegate.deactivateFrame(f);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#deiconifyFrame(javax.swing.JInternalFrame)
	 */
	public void deiconifyFrame(JInternalFrame f)
	{
		delegate.deiconifyFrame(f);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#iconifyFrame(javax.swing.JInternalFrame)
	 */
	public void iconifyFrame(JInternalFrame f)
	{
		delegate.iconifyFrame(f);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#maximizeFrame(javax.swing.JInternalFrame)
	 */
	public void maximizeFrame(JInternalFrame f)
	{
		delegate.maximizeFrame(f);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#minimizeFrame(javax.swing.JInternalFrame)
	 */
	public void minimizeFrame(JInternalFrame f)
	{
		delegate.minimizeFrame(f);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.DesktopManager#openFrame(javax.swing.JInternalFrame)
	 */
	public void openFrame(JInternalFrame f)
	{
		delegate.openFrame(f);
	}

	private void setAllSize(Dimension d)
	{
		desktop.setMinimumSize(d);
		desktop.setMaximumSize(d);
		desktop.setPreferredSize(d);
	}

	private void resizeDesktop()
	{
		if (desktop.isVisible()) {
			int x = 0;
			int y = 0;

			if (desktopScroller != null) {
				log.trace("Desktop resized, recalculating desktop dimension") ;
				JInternalFrame allFrames[] = desktop.getAllFrames();
				for (int i = 0; i < allFrames.length; i++) {
					x = Math.max(x, allFrames[i].getX()
							+ allFrames[i].getWidth());
					y = Math.max(y, allFrames[i].getY()
							+ allFrames[i].getHeight());
				}
				Dimension d = desktopScroller.getVisibleRect().getSize();
				if (desktopScroller.getBorder() != null) {
					Insets scrollInsets = desktopScroller.getBorder()
							.getBorderInsets(desktopScroller);
					d.setSize(d.getWidth() - scrollInsets.left
							- scrollInsets.right, d.getHeight()
							- scrollInsets.top - scrollInsets.bottom);
				}

				if (x <= d.getWidth())
					x = ((int) d.getWidth()) - 20;
				if (y <= d.getHeight())
					y = ((int) d.getHeight()) - 20;
				setAllSize(new Dimension(x, y));
				desktopScroller.invalidate();
				desktopScroller.validate();
			}
		}
	}
}
